package main

import (
	"flag"
	"fmt"
	kitLog "github.com/go-kit/kit/log"
	kitHttp "github.com/go-kit/kit/transport/http"
	"github.com/gorilla/mux"
	"gokit/services"
	"gokit/util"
	"golang.org/x/time/rate"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
)

func main() {
	// 1.控制台输入参数
	name := flag.String("name", "", "服务名称")
	port := flag.Int("p", 0, "端口名称")
	flag.Parse()
	if *name == "" {
		log.Fatal("请输入服务名")
		return
	}
	if *port == 0 {
		log.Fatal("请输入服务名")
		return
	}
	// 设置参数
	util.SetServiceNameAndPort(*name, *port)
	// http://localhost:8080/user/101
	// go run main.go --name userService -p 8080
	// go run main.go --name userService -p 8081
	// go run main.go --name userService -p 8082

	// 3.创建服务并注册服务
	userService := services.NewUserService()

	// Service 层，最原始的 endPoint
	endPoint := services.GenUserEndPoint(userService)

	// 加入限流中间件
	limiter := rate.NewLimiter(1, 5) // 创建桶
	middlewareEndPoint := services.RateLimit(limiter)(endPoint)

	// 加入日志中间件
	var logger kitLog.Logger
	logger = kitLog.NewLogfmtLogger(os.Stdout)
	logger = kitLog.WithPrefix(logger, "mykit", "1.0")
	logger = kitLog.WithPrefix(logger, "time", kitLog.DefaultTimestampUTC) //加上前缀时间
	logger = kitLog.WithPrefix(logger, "caller", kitLog.DefaultCaller)     //加上前缀，日志输出时的文件和第几行代码
	middlewareEndPoint = services.UserServiceLogMiddleware(logger)(middlewareEndPoint)

	// CheckTokenMiddleware 中间件
	middlewareEndPoint = services.CheckTokenMiddleware()(middlewareEndPoint)

	// services.DecodeUserRequest(请求,类似controller) -> endPoint(处理业务逻辑,services) -> services.EncodeUserResponse(响应,返回给视图)
	// 限流前写法
	// serverHandler := kitHttp.NewServer(endPoint, services.DecodeUserRequest, services.EncodeUserResponse)

	// 限流后写法
	serverHandler := kitHttp.NewServer(
		middlewareEndPoint,
		services.DecodeUserRequest,
		services.EncodeUserResponse,
		kitHttp.ServerErrorEncoder(services.MyErrorEncoder), // 自定义返回错误,覆盖内部 errorEncoder: DefaultErrorEncoder,
	)

	// 增加handler用于获取token
	accessService := services.NewAccessService()
	accessServiceEndpoint := services.AccessEndpoint(accessService)
	accessHandler := kitHttp.NewServer(
		accessServiceEndpoint,
		services.DecodeAccessRequest,
		services.EncodeAccessResponse,
	)

	//http.Handle("/user", serverHandler)
	//http.ListenAndServe(":8080", nil)

	router := mux.NewRouter()
	//router.Handle("/user/{uid:[0-9]+}", serverHandler).Methods("GET")
	router.Methods("POST").Path("/access-token").Handler(accessHandler) //注册token获取的handler，生成token
	router.Methods("GET", "DELETE").Path("/user/{uid:[0-9]+}").Handler(serverHandler)

	// 健康检查
	router.Methods("GET").Path("/health").HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {
		writer.Header().Set("Content-type", "application/json")
		_, _ = writer.Write([]byte(`{"status": "ok"}`))
	})

	// 实现服务启动失败，服务注销
	// 定义补获错误的通道，只要有错误，就注销服务
	errChan := make(chan error)

	// 服务启动成功，注册服务
	go func() {
		addr := fmt.Sprintf(":%d", *port) //":8080"
		log.Println(fmt.Sprintf("http://localhost%s", addr))
		// 服务注册
		util.ServiceRegister()
		err := http.ListenAndServe(addr, router)
		// 服务报错，写入错误
		if err != nil {
			errChan <- err
		}
	}()

	// 监听程序退出
	go func() {
		signalChan := make(chan os.Signal)
		// https://www.jianshu.com/p/ae72ad58ecb6
		// ctrl + c 信号 syscall.SIGINT
		// pkill 信号 syscall.SIGTERM
		signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
		// 退出写入错误
		errChan <- fmt.Errorf("%s", <-signalChan)
	}()

	// 同步通道，这里没有数据写入会一直阻塞，有数据写入继续执行
	getErr := <-errChan
	util.ServiceDeregister() // 服务注销
	log.Println(getErr)
}
